package com.ywr;

import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author jm017801
 */
@Slf4j
public class ApiSignUtil {

    private ApiSignUtil() {
    }

    /**
     * 签名超时时长，默认时间为5分钟，ms
     */
    private static final int SIGN_EXPIRED_TIME = 5 * 60 * 1000;
    /**
     * "classpath:api-sign-key.properties";
     * 1 营销使用
     * 2 c端发券使用
     */
    private static final String API_SIGN_KEY_CONFIG_PATH = "nNtxqWYhFqpsuJtZG7WIOt04NEQFFzRp:5Na7toP137ETxnv&I^ohPmu3gUse9ijL\n9DDE360102C103867BD2F45872F1129C:25A8CE08B56217EFF55CC0CCA382613D";

    private static final String SIGN_KEY = "sign";

    private static final String TIMESTAMP_KEY = "timestamp";

    private static final String ACCESS_KEY = "accessKey";

    private static final String ACCESS_SECRET = "accessSecret";

    private static Map<String, String> map = new ConcurrentHashMap<>();


    static {
        Properties properties = new Properties();
        try {
            properties.load(new StringReader(API_SIGN_KEY_CONFIG_PATH));
        } catch (IOException e) {
            log.error("加载配置信息错误：{}", e.getMessage());
        }
        for (Object key : properties.keySet()) {
            map.put(String.valueOf(key), properties.getProperty(String.valueOf(key)));
        }


    }

    public static boolean preHandle(String bodyString) {
        JSONObject params = new JSONObject(bodyString);
        String timestamp = params.getStr(TIMESTAMP_KEY);
        String accessKey = params.getStr(ACCESS_KEY);
        String accessSecret = map.get(accessKey);
        if (!StringUtils.isNumeric(timestamp)) {
            throw new VoucherClientException(INVALID_REQUEST_TIME);
        }
        // 检查KEY是否合理
        if (StringUtils.isEmpty(accessKey) || StringUtils.isEmpty(accessSecret)) {
            throw new VoucherClientException(INVALID_SIGN_KEY);
        }
        long ts = Long.parseLong(timestamp);
        // 禁止超时签名
        if (System.currentTimeMillis() - ts > SIGN_EXPIRED_TIME) {
            throw new VoucherClientException(REQUEST_TIMEOUT);
        }
        if (!verificationSign(params, accessSecret)) {
            throw new VoucherClientException(SIGN_ERROR);
        }
        return true;
    }

    private static boolean verificationSign(JSONObject requestParams, String accessSecret) {
        Set<Map.Entry<String, Object>> pNames = requestParams.entrySet();
        Map<String, Object> params = new HashMap<>(16);
        pNames.forEach(item -> {
            if (!SIGN_KEY.equals(item.getKey())) {
                Object pValue = requestParams.get(item.getKey());
                params.put(item.getKey(), pValue);
            }
        });
        String originSign = requestParams.getStr(SIGN_KEY);
        String sign = createSign(params, accessSecret);
        return sign.equals(originSign);
    }

    public static String createSign(Map<String, Object> params, String accessSecret) {
        Set<String> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuilder temp = new StringBuilder();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = String.valueOf(value);
            }
            temp.append(valueString);
        }
        temp.append("&").append(ACCESS_SECRET).append("=").append(accessSecret);
        log.info("temp: {}",temp);
        return new Digester(DigestAlgorithm.MD5).digestHex(temp.toString()).toUpperCase();
    }
}
